From 88684baecf164875f5947a9eff40f567aa172c67 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 22 Nov 2017 14:19:02 +0100 Subject: [PATCH] clipboard: Add gdk_clipboard_read_text_async() Also add deserializers for G_TYPE_STRING. --- gdk/gdkclipboard.c | 64 ++++++++++++++++++++++++++++ gdk/gdkclipboard.h | 9 ++++ gdk/gdkcontentdeserializer.c | 82 ++++++++++++++++++++++++++++++++++++ tests/testclipboard2.c | 36 ++++++++++++++++ 4 files changed, 191 insertions(+) diff --git a/gdk/gdkclipboard.c b/gdk/gdkclipboard.c index 67bafbabb9..2b37270315 100644 --- a/gdk/gdkclipboard.c +++ b/gdk/gdkclipboard.c @@ -546,6 +546,70 @@ gdk_clipboard_read_pixbuf_finish (GdkClipboard *clipboard, return g_value_dup_object (value); } +/** + * gdk_clipboard_read_text_async: + * @clipboard: a #GdkClipboard + * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. + * @callback: (scope async): callback to call when the request is satisfied + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously request the @clipboard contents converted to a string. + * When the operation is finished @callback will be called. You can then + * call gdk_clipboard_read_text_finish() to get the result. + * + * This is a simple wrapper around gdk_clipboard_read_value_async(). Use + * that function or gdk_clipboard_read_async() directly if you need more + * control over the operation. + **/ +void +gdk_clipboard_read_text_async (GdkClipboard *clipboard, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (GDK_IS_CLIPBOARD (clipboard)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (callback != NULL); + + gdk_clipboard_read_value_internal (clipboard, + G_TYPE_STRING, + gdk_clipboard_read_text_async, + G_PRIORITY_DEFAULT, + cancellable, + callback, + user_data); +} + +/** + * gdk_clipboard_read_text_finish: + * @clipboard: a #GdkClipboard + * @result: a #GAsyncResult + * @error: a #GError location to store the error occurring, or %NULL to + * ignore. + * + * Finishes an asynchronous clipboard read started with + * gdk_clipboard_read_text_async(). + * + * Returns: (transfer full) (nullable): a new string or %NULL on error. + **/ +char * +gdk_clipboard_read_text_finish (GdkClipboard *clipboard, + GAsyncResult *res, + GError **error) +{ + const GValue *value; + + g_return_val_if_fail (g_task_is_valid (res, clipboard), NULL); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (res)) == gdk_clipboard_read_text_async, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + value = g_task_propagate_pointer (G_TASK (res), error); + if (!value) + return NULL; + + return g_value_dup_string (value); +} + GdkClipboard * gdk_clipboard_new (GdkDisplay *display) { diff --git a/gdk/gdkclipboard.h b/gdk/gdkclipboard.h index f9a6f14fc0..9fce851040 100644 --- a/gdk/gdkclipboard.h +++ b/gdk/gdkclipboard.h @@ -74,6 +74,15 @@ GDK_AVAILABLE_IN_3_94 GdkPixbuf * gdk_clipboard_read_pixbuf_finish(GdkClipboard *clipboard, GAsyncResult *res, GError **error); +GDK_AVAILABLE_IN_3_94 +void gdk_clipboard_read_text_async (GdkClipboard *clipboard, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GDK_AVAILABLE_IN_3_94 +char * gdk_clipboard_read_text_finish (GdkClipboard *clipboard, + GAsyncResult *res, + GError **error); G_END_DECLS diff --git a/gdk/gdkcontentdeserializer.c b/gdk/gdkcontentdeserializer.c index d6ec674b27..bcfc11e7e1 100644 --- a/gdk/gdkcontentdeserializer.c +++ b/gdk/gdkcontentdeserializer.c @@ -432,11 +432,73 @@ pixbuf_deserializer (GdkContentDeserializer *deserializer) deserializer); } +static void +string_deserializer_finish (GObject *source, + GAsyncResult *result, + gpointer deserializer) +{ + GOutputStream *stream = G_OUTPUT_STREAM (source); + GError *error = NULL; + gssize written; + + written = g_output_stream_splice_finish (stream, result, &error); + if (written < 0) + { + gdk_content_deserializer_return_error (deserializer, error); + return; + } + else if (written == 0) + { + /* Never return NULL, we only return that on error */ + g_value_set_string (gdk_content_deserializer_get_value (deserializer), ""); + } + else + { + g_value_take_string (gdk_content_deserializer_get_value (deserializer), + g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM ( + g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (stream))))); + } + gdk_content_deserializer_return_success (deserializer); +} + +static void +string_deserializer (GdkContentDeserializer *deserializer) +{ + GOutputStream *output, *filter; + GCharsetConverter *converter; + GError *error = NULL; + + converter = g_charset_converter_new ("utf-8", + gdk_content_deserializer_get_user_data (deserializer), + &error); + if (converter == NULL) + { + gdk_content_deserializer_return_error (deserializer, error); + return; + } + g_charset_converter_set_use_fallback (converter, TRUE); + + output = g_memory_output_stream_new_resizable (); + filter = g_converter_output_stream_new (output, G_CONVERTER (converter)); + g_object_unref (output); + g_object_unref (converter); + + g_output_stream_splice_async (filter, + gdk_content_deserializer_get_input_stream (deserializer), + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + gdk_content_deserializer_get_priority (deserializer), + gdk_content_deserializer_get_cancellable (deserializer), + string_deserializer_finish, + deserializer); + g_object_unref (filter); +} + static void init (void) { static gboolean initialized = FALSE; GSList *formats, *f; + const char *charset; if (initialized) return; @@ -483,5 +545,25 @@ init (void) } g_slist_free (formats); + + gdk_content_register_deserializer ("text/plain;charset=utf-8", + G_TYPE_STRING, + string_deserializer, + (gpointer) "utf-8", + NULL); + if (!g_get_charset (&charset)) + { + char *mime = g_strdup_printf ("text/plain;charset=%s", charset); + gdk_content_register_deserializer (mime, + G_TYPE_STRING, + string_deserializer, + mime, + g_free); + } + gdk_content_register_deserializer ("text/plain", + G_TYPE_STRING, + string_deserializer, + (gpointer) "ASCII", + NULL); } diff --git a/tests/testclipboard2.c b/tests/testclipboard2.c index 31efc64e0d..23eddfe6d9 100644 --- a/tests/testclipboard2.c +++ b/tests/testclipboard2.c @@ -27,6 +27,9 @@ clipboard_changed_cb (GdkClipboard *clipboard, child = gtk_stack_get_child_by_name (GTK_STACK (stack), "image"); gtk_image_clear (GTK_IMAGE (child)); + + child = gtk_stack_get_child_by_name (GTK_STACK (stack), "text"); + gtk_label_set_text (GTK_LABEL (child), ""); } static void @@ -49,6 +52,26 @@ pixbuf_loaded_cb (GObject *clipboard, g_object_unref (pixbuf); } +static void +text_loaded_cb (GObject *clipboard, + GAsyncResult *res, + gpointer data) +{ + GError *error = NULL; + char *text; + + text = gdk_clipboard_read_text_finish (GDK_CLIPBOARD (clipboard), res, &error); + if (text == NULL) + { + g_print ("%s\n", error->message); + g_error_free (error); + return; + } + + gtk_label_set_text (data, text); + g_free (text); +} + static void visible_child_changed_cb (GtkWidget *stack, GParamSpec *pspec, @@ -69,6 +92,15 @@ visible_child_changed_cb (GtkWidget *stack, pixbuf_loaded_cb, image); } + else if (g_str_equal (visible_child, "text")) + { + GtkWidget *label = gtk_stack_get_child_by_name (GTK_STACK (stack), "text"); + + gdk_clipboard_read_text_async (clipboard, + NULL, + text_loaded_cb, + label); + } } static void @@ -103,6 +135,10 @@ get_contents_widget (GdkClipboard *clipboard) child = gtk_image_new (); gtk_stack_add_titled (GTK_STACK (stack), child, "image", "Image"); + child = gtk_label_new (NULL); + gtk_label_set_line_wrap (GTK_LABEL (child), TRUE); + gtk_stack_add_titled (GTK_STACK (stack), child, "text", "Text"); + return stack; } -- 2.30.2